package com.browsesoft.htmlcomponent;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import com.aote.model.DataShowTableModel;
import com.aote.model.DoNotClearData;
import com.browsesoft.ExtendElement;
import com.browsesoft.baseadapter.AddupModel;
import com.browsesoft.baseadapter.SumModel;

/**
 * 翻页表格组件
 * 
 * @author Browsesoft
 * @version 1.0
 */
public class HTMLPageTableComponent extends HTMLTableComponent {
	/**
	 * 页面大小，每页显示的行数
	 */
	protected int rowsOfPage = 10;

	/**
	 * 当前页号
	 */
	public int pageNumber = 1;

	/**
	 * 小计行的单元格
	 */
	protected Element addupTD;

	/**
	 * 总计行的单元格
	 */
	protected Element sumTD;

	/**
	 * 总计行
	 */
	protected Element sumTR;

	/**
	 * 总计行要插入的位置
	 */
	protected Element table;

	/**
	 * 总行数，组件显示完后，数据会清除掉。每次清除数据时，设置总行数。
	 */
	private int rowNum;
	
	/**
	 * 构造器
	 * 
	 * @param parent
	 *            组件的父组件
	 * @throws Exception
	 */
	public HTMLPageTableComponent(HTMLBasicComponent parent) throws Exception {
		super(parent);
	}

	/**
	 * 初始化
	 * 
	 * @param request
	 * @param e
	 * @throws Exception
	 */
	public void init(HttpServletRequest request, Element e) throws Exception {
		// 创建子组件并保存组件元素
		super.init(request, e);
		// 设置页面默认行数
		this.setRowsOfPage(request);
		this.createInitTableTail();
		// 得到模板中总计行
		Iterator iter = ExtendElement.findElements(this.element, "type", "sum")
				.iterator();
		if (iter.hasNext()) {
			// 总计行
			Element item = (Element) iter.next();
			this.sumTR = (Element) item.cloneNode(true);
			// 总计行的父元素
			this.table = (Element) item.getParentNode();
			// 总计单元格
			this.sumTD = (Element) ExtendElement.findElements(this.sumTR,
					"type", "addup").iterator().next();
		}
	}

	/**
	 * 得到页面的默认行数
	 */
	private void setRowsOfPage(HttpServletRequest request) {
		try {
			// 如果配置了页面默认行数产生器
			if (this.element.hasAttribute("tablerowscreator")) {
				// 让页面行数产生器产生行数
				String rowsCreator = this.getElement().getAttribute(
						"tablerowscreator");
				TableRowsCreator creator = (TableRowsCreator) Class.forName(
						rowsCreator).newInstance();
				this.rowsOfPage = creator.getRowsOfPage(request, this.element);
				return;
			}
		} catch (TableRowsCreateException ex1) {
			// 忽略掉产生行号异常
		} catch (InstantiationException ex1) {
			throw new RuntimeException(ex1);
		} catch (IllegalAccessException ex1) {
			throw new RuntimeException(ex1);
		} catch (ClassNotFoundException ex1) {
			throw new RuntimeException(ex1);
		}
		// 从模板上得行数
		String rowcount = this.getElement().getAttribute("rowcount");
		if (rowcount != null && !rowcount.equals("")) {
			try {
				this.rowsOfPage = Integer.parseInt(rowcount);
			} catch (NumberFormatException ex) {
				System.out.println("页面默认行数错误!");
			}
		}
	}

	/**
	 * 根据Model的内容更新需要处理的元素内容，在产生页面时要调用
	 * 
	 * @throws java.lang.Exception
	 */
	public void updateElement() throws Exception {
		super.updateElement();
		// 构造表尾
		createTableTail();
		// 清除数据，清除前，保存总行数，以便外面调用
		if (canClearDatas()) {
			this.rowNum = ((HTMLTableModel) model).getRowCount();
			((DataShowTableModel) this.model).clearDatas();
		}
	}

	/**
	 * 判断model是否可清除数据
	 */
	private boolean canClearDatas() {
		// 如果实现了不可清除接口
		if (this.model instanceof DoNotClearData) {
			return false;
		}
		// 如果组件有不清除标记，不清除
		if (this.getElement().hasAttribute("noclear")) {
			return false;
		}
		// 如果不时DataShowTableModel,不清除
		if (!(this.model instanceof DataShowTableModel)) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 初始化时调用的构造表尾方法
	 */
	public void createInitTableTail() {
		// 得到隐藏域name属性，并替换掉它的属性
		LinkedList list = ExtendElement.findElements(element, "name", "option");
		if (list.size() > 0) {
			Element option = (Element) list.get(0);
			option.setAttribute("name", "a" + this.name.concat("_option"));
		}
		// 得到所有的翻页按钮。并替换掉它的onclick属性
		LinkedList buttons = ExtendElement.findElements(element, "type",
				"tbutton");
		for (int i = 0; i < buttons.size(); i++) {
			Element e = (Element) buttons.get(i);
			String temp = e.getAttribute("onclick").replaceAll("option",
					"a" + this.name.concat("_option"));
			e.setAttribute("onclick", temp);
		}
		// 修改到第几页元素属性
		list = ExtendElement.findElements(element, "name", "pagenumber");
		if (list.size() > 0) {
			Element pageNum = (Element) list.get(0);
			pageNum.setAttribute("name", getName().concat(".pagenumber"));
		}
		// 修改每一页多少行元素属性
		list = ExtendElement.findElements(element, "name", "rownumber");
		if (list.size() > 0) {
			Element rowNumber = (Element) list.get(0);
			rowNumber.setAttribute("name", getName().concat(".rownumber"));
		}
	}

	/**
	 * 构造表尾
	 */
	public void createPage() {
		// 构造显示总页数
		List l = ExtendElement.findElements(element, "type", "totalPage");
		if (!l.isEmpty()) {
			Element totalPage = (Element) l.get(0);
			Text totalText = ((HTMLPage) getPage()).getDocument()
					.createTextNode(Integer.toString(getInnerPageCount()));
			ExtendElement.replaceElementContext(totalPage, totalText);
		}
		// 构造共有多少项
		LinkedList v = ExtendElement.findElements(element, "type", "totalitem");
		if (v.size() != 0) {
			Element totalItem = (Element) v.get(0);
			if (totalItem != null) {
				Text ItemText = ((HTMLPage) getPage()).getDocument()
						.createTextNode(
								Integer.toString(((HTMLTableModel) this.model)
										.getRowCount()));
				ExtendElement.replaceElementContext(totalItem, ItemText);
			}
		}
		// 构造显示第几页
		LinkedList list1 = ExtendElement.findElements(element, "type",
				"currentPage");
		if (!list1.isEmpty()) {
			Element currentPage = (Element) list1.get(0);
			Text currentText = ((HTMLPage) getPage()).getDocument()
					.createTextNode(Integer.toString(pageNumber));
			ExtendElement.replaceElementContext(currentPage, currentText);
		}
		// 修改到第几页元素属性
		List list = ExtendElement.findElements(element, "name", getName()
				.concat(".pagenumber"));
		if (list.size() > 0) {
			Element pageNum = (Element) list.get(0);
			pageNum.setAttribute("value", Integer.toString(this.pageNumber));
		}
		// 修改每一页多少行属性
		list = ExtendElement.findElements(element, "name", getName().concat(
				".rownumber"));
		if (list.size() > 0) {
			Element rowNumber = (Element) list.get(0);
			rowNumber.setAttribute("value", Integer.toString(this.rowsOfPage));
		}
	}

	/**
	 * 处理用户请求，将需要Model处理的内容提交给Model
	 * 
	 * @param request
	 *            客户端请求
	 * @throws java.lang.Exception
	 */
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		super.service(request, response);
		// 设置每页的行数
		String value = request.getParameter(name.concat(".rownumber"));
		if (value != null && !value.trim().equals("")) {
			int rowNumber = Integer.parseInt(value);
			this.rowsOfPage = rowNumber;
			goCurrentPage(1);
		}
		// 设置到第几页
		value = request.getParameter(name.concat(".pagenumber"));
		if (value != null && !value.trim().equals("")) {
			int page = Integer.parseInt(value);
			goCurrentPage(page);
		}
		// 设置翻页选项
		String option = request.getParameter("a" + name.concat("_option"));
		if ((option != null)) {
			// 到第一页
			if (option.equals("first")) {
				goCurrentPage(1);
			}
			// 到前一页
			else if (option.equals("previous")) {
				goCurrentPage(this.pageNumber - 1);
			}
			// 到下一页
			else if (option.equals("next")) {
				goCurrentPage(this.pageNumber + 1);
			}
			// 到最后一页
			else if (option.equals("last")) {
				goCurrentPage(this.getInnerPageCount());
			}
		}
	}

	/**
	 * 到指定页 pointPage 页号
	 */
	protected void goCurrentPage(int pointPage) {
		// 设置当前页号
		if (pointPage <= 1) {
			this.pageNumber = 1;
		} else if (pointPage > getInnerPageCount()) {
			this.pageNumber = getInnerPageCount();
		} else {
			pageNumber = pointPage;
		}
	}

	/**
	 * 返回总页数，内部使用
	 * 
	 * @return 总页数
	 */
	private int getInnerPageCount() {
		return (((HTMLTableModel) model).getRowCount() - 1) / rowsOfPage + 1;
	}
	
	/**
	 * 返回总页数，外部使用
	 */
	public int getPageCount() {
		return (this.rowNum - 1) / rowsOfPage + 1;
	}

	protected void createTableRows() {
		createTableRows((pageNumber - 1) * rowsOfPage, pageNumber * rowsOfPage);
	}

	/**
	 * 构造表尾
	 */
	public void createTableTail() throws Exception {
		// 得到模板中小计行
		Iterator iter = ExtendElement.findElementsByTagName(this.element, "tr",
				"type", "addup").iterator();
		// 如果有小计行
		if (iter.hasNext()) {
			// 创建小计行
			this.createAddup(((HTMLPage) getPage()).getDocument(),
					(Element) iter.next());
		}
		// 如果有总计行
		if (this.sumTR != null) {
			// 清除总计行
			ExtendElement.removeChilds(this.table, "type", "sum");
			// 如果是最后一页
			if (this.pageNumber == this.getInnerPageCount()) {
				Element tr = (Element) this.sumTR.cloneNode(true);
				// 构造总计行
				this.createSum(((HTMLPage) getPage()).getDocument(), tr);
				Element oldTr = (Element) ExtendElement.findElementsByTagName(
						this.element, "tr", "type", "sum").get(0);
				table.replaceChild(tr, oldTr);

			}
		}
		// 构造翻页行
		this.createPage();
	}

	/**
	 * 构造小计行
	 * 
	 * @param tr
	 *            小计在模板中所对应的行元素
	 * @param doc
	 *            页面所对应的文档
	 */
	public void createAddup(Document doc, Element tr) throws Exception {
		// 如果小计单元格不存在
		if (this.addupTD == null) {
			// 取出小计单元格
			this.addupTD = (Element) ExtendElement.findElements(tr, "type",
					"addup").iterator().next();
		}
		Element template = (Element) tr.getElementsByTagName("template")
				.item(0);
		// 清除小计行
		ExtendElement.removeChilds(template);
		// 对于每一列
		int columnCount = ((HTMLTableModel) model).getColumnCount();
		for (int i = 0; i < columnCount; i++) {
			Element e = (Element) addupTD.cloneNode(true);
			// 让model修改单元格
			((AddupModel) model).modifyAddupCell(doc, e, i);
			template.appendChild(e);
		}
	}

	/**
	 * 构造总计行
	 * 
	 * @param tr
	 *            总计在模板中所对应的行元素
	 * @param doc
	 *            页面所对应的文档
	 */
	public void createSum(Document doc, Element tr) throws Exception {
		Element template = (Element) tr.getElementsByTagName("template")
				.item(0);
		// 将总计行清除
		ExtendElement.removeChilds(template);
		// 对于每一列
		int columnCount = ((HTMLTableModel) model).getColumnCount();
		for (int i = 0; i < columnCount; i++) {
			// 得到需修改的单元格
			Element e = (Element) this.sumTD.cloneNode(true);
			// 让model修改单元格
			((SumModel) model).modifySumCell(doc, e, i);
			// 将修改好的单元格挂到template下
			template.appendChild(e);
		}
	}
}